﻿// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved

#include "stdafx.h"
#include "HttpRequest.h"
#include "Encode.h"

#define FILE_ACTION_TRAP        0x000100
#define FILE_ACTION_DEHYDRATE   0x00200

//===============================================================
// CloudProviderSyncRootWatcher
//
//   This class watches for any changes that happen to files
//   and folders in the Sync Root on the client machine. This
//   allows for hydration to be signalled or other actions.
//
// Fakery Factor:
//
//   This class is pretty usable as-is. You will probably want to
//   get rid of that whole Ctrl-C shenanigans thing to stop the
//   watcher and replace it with code that's called by some UI
//   you do to uninstall.
//
//===============================================================

DirectoryWatcher CloudProviderSyncRootWatcher::s_directoryWatcher;
bool CloudProviderSyncRootWatcher::s_shutdownWatcher;

std::list <WatchObject> CloudProviderSyncRootWatcher::objectList;
bool  CloudProviderSyncRootWatcher::service_exit_flag = false;
bool  CloudProviderSyncRootWatcher::service_exit_flag_ack = false;

using namespace std;

void CloudProviderSyncRootWatcher::WatchAndWait()
{
    //  Main loop - wait for Ctrl+C or our named event to be signaled
    SetConsoleCtrlHandler(Stop, TRUE);
    InitDirectoryWatcher();


    while (true)
    {
        try
        {
            auto task = s_directoryWatcher.ReadChangesAsync();

            while (!task.is_done())
            {
                Sleep(1000);

                if (s_shutdownWatcher)
                {
                    s_directoryWatcher.Cancel();
                    task.wait();
                    service_exit_flag = true;

                    while (service_exit_flag_ack == false)
                    {
                        Sleep(1000);
                    }

                }
            }

            if (s_shutdownWatcher)
            {
                break;
            }
        }
        catch (...)
        {
            std::wprintf(L"CloudProviderSyncRootWatcher watcher failed.\n");
            throw;
        }
    }
}


std::string wstringToString(const std::wstring& wstr)
{
    LPCWSTR pwszSrc = wstr.c_str();
    int nLen = WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, NULL, 0, NULL, NULL);
    if (nLen == 0)
        return std::string("");

    char* pszDst = new char[nLen];
    if (!pszDst)
        return std::string("");

    WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, pszDst, nLen, NULL, NULL);
    std::string str(pszDst);
    delete[] pszDst;
    pszDst = NULL;

    return str;

}


std::wstring stringToWstring(std::string str)
{
    std::wstring result;
    //获取缓冲区大小，并申请空间，缓冲区大小按字符计算  
    int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
    TCHAR* buffer = new TCHAR[len + 1];
    //多字节编码转换成宽字节编码  
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
    buffer[len] = '\0';             //添加字符串结尾  
    //删除缓冲区并返回值  
    result.append(buffer);
    delete[] buffer;
    return result;
}


std::string & replace_all(std::string& str, const  std::string& old_value, const  std::string& new_value)
{
     while (true)
    {
         std::string::size_type   pos(0);
         if ((pos = str.find(old_value)) != std::string::npos)
         {
               str.replace(pos, old_value.length(), new_value);
         }
        else { break; }
    }
     return   str;
}

std::string  updateCloudPath(std::wstring  localPath)
{
    std::string cloudlpath = wstringToString(localPath.c_str());
    //去掉绝对路径前缀
    std::string clientpath = wstringToString(ProviderFolderLocations::GetClientFolder()).c_str();

    cloudlpath.erase(0, clientpath.length() + 1);

    replace_all(cloudlpath, "\\", "/");

    return cloudlpath;
}


vector<string> split(const string& s, const string& seperator) {
    vector<string> result;
    typedef string::size_type string_size;
    string_size i = 0;

    while (i != s.size()) {
        //找到字符串中首个不等于分隔符的字母；
        int flag = 0;
        while (i != s.size() && flag == 0) {
            flag = 1;
            for (string_size x = 0; x < seperator.size(); ++x)
                if (s[i] == seperator[x]) {
                    ++i;
                    flag = 0;
                    break;
                }
        }

        //找到又一个分隔符，将两个分隔符之间的字符串取出；
        flag = 0;
        string_size j = i;
        while (j != s.size() && flag == 0) {
            for (string_size x = 0; x < seperator.size(); ++x)
                if (s[j] == seperator[x]) {
                    flag = 1;
                    break;
                }
            if (flag == 0)
                ++j;
        }
        if (i != j) {
            result.push_back(s.substr(i, j - i));
            i = j;
        }
    }
    return result;
}

string  getBaseFromPath(std::string path)
{
    vector<string> v = split(path, "\\");
    if (v.size() > 0)
        return v[v.size() - 1];
    
    return "";
}

int ignoreFile(std::string path, bool checkattrib)
{
    //need add attrib check 
    WIN32_FIND_DATAW wfd; //数据结构;
        
    if (checkattrib == true)
    {
        HANDLE hFile = FindFirstFile(stringToWstring(path).c_str(), &wfd);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            printf("%s   get  attrib  err ! \n", path.c_str());
            return 1;
        }
        FindClose(hFile);

        if (wfd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
        {
            printf("ignore file  %s  attrib  %x  ! \n", path.c_str(), wfd.dwFileAttributes);
            return 1;
        }
    }
       //    printf("%s   attrib  %x \n", path.c_str(), wfd.dwFileAttributes);

    std::string::size_type   pos(0);
    string name = getBaseFromPath(path);
    pos = name.find("~$");
    //printf("name %s , pos %d \n", path.c_str(), pos);
    if (pos == 0)
        return 1;
    
    pos = name.find("~");
    if (pos == 0)
        return 1;


    return 0;
}

int setCloudSyncState(wstring Path, bool convert,  long dirflag)
{
    HRESULT result;
    USN  usn = 0;

    winrt::handle placeholder(CreateFile(Path.c_str(), 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, dirflag, nullptr));
    if (placeholder.get() == (HANDLE)-1)
    {
        printf(" file name %s , place holder error %x ! \n", wstringToString(Path).c_str(), GetLastError());
        return -1;
        //这里是否会一直循环，需要确认
    }

    if (convert)
    {
        result = CfConvertToPlaceholder(placeholder.get(), Path.data(), (USHORT)(wcslen(Path.data()) + 1) * sizeof(WCHAR), CF_CONVERT_FLAG_MARK_IN_SYNC, &usn, NULL);
        if (result != 0)
            printf("CfConvertToPlaceholder HRESULT  %x , USN  %lld \n", result, usn);
    }

    //这里会触发再次同步
    result = CfSetInSyncState(placeholder.get(), CF_IN_SYNC_STATE_IN_SYNC, CF_SET_IN_SYNC_FLAG_NONE, &usn);
    if (result != 0)
        printf("CfSetInSyncState HRESULT  %x , USN  %lld \n", result, usn);

    return result;

}

int getCloudSyncState(wstring CheckPath, long flag)
{
    DWORD  ReturnedLength;
    CF_PLACEHOLDER_STANDARD_INFO* info = (CF_PLACEHOLDER_STANDARD_INFO*)malloc(sizeof(CF_PLACEHOLDER_STANDARD_INFO) + 500);
    int ret = CF_IN_SYNC_STATE_NOT_IN_SYNC;

    if (info != NULL)
    {
         
        winrt::handle placeholder(CreateFile(CheckPath.c_str(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, flag, nullptr));
        if (placeholder.get() == INVALID_HANDLE_VALUE)
        {
            printf(" placeholder  %s , get  error %x ! \n", wstringToString(CheckPath).c_str(), GetLastError());
            free(info);
            return 0 - GetLastError();
        }

        HRESULT result = CfGetPlaceholderInfo(placeholder.get(), CF_PLACEHOLDER_INFO_STANDARD, info, sizeof(CF_PLACEHOLDER_STANDARD_INFO) + 500, &ReturnedLength);
        if (result == 0)
        {
            ret = info->InSyncState;
        }
        else {
            printf(" file name %s , get info error %x ! \n", wstringToString(CheckPath).c_str(), result);
            ret = result;
        }

        free(info);
    }

    return ret;
}

#if 1
bool CloudProviderSyncRootWatcher::TravelPath(std::wstring  path)// 遍历搜索目录
{
    HANDLE hFile;
    WIN32_FIND_DATAW wfd; //数据结构;
    
    printf("TravelPath  %s \n", wstringToString(path).c_str());

    //匹配任何文件包括文件夹目录;
    std::wstring Path = path + L"\\*.*";
    hFile = FindFirstFile(Path.c_str(), &wfd);
    
    if (hFile != INVALID_HANDLE_VALUE)
    {
        do
        {
            if (wfd.cFileName[0] == '.') //如果是.或..则过滤; 
                continue;

            
            std::wstring CheckPath = path + L"\\" + std::wstring(wfd.cFileName);

            if (ignoreFile(wstringToString(CheckPath), true))
                continue;

            printf(" show file name %s , attrib %x  \n", wstringToString(CheckPath).c_str(), wfd.dwFileAttributes);

            if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //如果是目录则递归;
            {
               TravelPath(CheckPath);               //调用递归;
            }
            else
            {
                WatchObject  o{ CheckPath, FILE_ACTION_ADDED };
                objectList.push_back(o);
                
            }
        } while (FindNextFile(hFile, &wfd));

        FindClose(hFile);
    }

    return true;
}

#if 0
void checkDirectSync(std::wstring path)
{
    vector<string> v = split(wstringToString(path), "\\");
    printf("checkDirectSync path: ");
    for (vector<string>::size_type i = 0; i != v.size(); ++i)
        printf("[%s] ", v[i].c_str());
    printf("\n");
        
    int PathLen = v.size() - 1;
    while (PathLen > 0)
    {
        std::wstring  checkParentPath = L"";
        
        for (vector<string>::size_type i = 0; i < PathLen; ++i)
        {
            if (checkParentPath != L"")
                checkParentPath = checkParentPath + L"\\";

            checkParentPath = checkParentPath + stringToWstring(v[i]);
        }

      
        printf("sysroot path:%s \n ", wstringToString(ProviderFolderLocations::GetClientFolder()).c_str());
        printf("checkDirectSync path: %s\n ", wstringToString(checkParentPath).c_str());

        if (checkParentPath == ProviderFolderLocations::GetClientFolder())
        {
            printf("until  sysroot \n");
            break;
        }

        if (TravelPath(checkParentPath) == false)
            break;


        PathLen--;
    }
}
#endif

#endif
void CloudProviderSyncRootWatcher::ServiceThread(LPVOID lpParam)
{

    while (!service_exit_flag) {
    
        if (objectList.empty()) {
            //太长则会出错, 改为出错，再加回队列
            Sleep(1000);
            continue;
        }
      
       
        auto object = objectList.front();
        objectList.pop_front(); 

#if 0
        //简单去重
        while (!objectList.empty())
        {
            auto otherobject = objectList.front();
            if (otherobject.path == object.path)
            {
           //     wprintf(L" object  path %s, %x \n", object.path.c_str(), object.action);
           //     wprintf(L" otherobject  path %s, %x \n", otherobject.path.c_str(), otherobject.action);

                //去掉重复action 上传
                if (object.action == FILE_ACTION_ADDED || object.action == FILE_ACTION_MODIFIED)
                {
                    if (otherobject.action ==  FILE_ACTION_ADDED || otherobject.action == FILE_ACTION_MODIFIED) {
                        objectList.pop_front();
                        continue;
                    }
                }
            }
            
            break;
            
        }
#endif

        if (object.action == FILE_ACTION_REMOVED) {

            //删除则不检查属性，因为读不到了
            if (ignoreFile(wstringToString(object.path), false))
            {
                printf("ignoreFile %s \n", wstringToString(object.path).c_str());
                continue;
            }

            wprintf(L"Remove file %s\n", object.path.c_str());
            HttpRequest  req("127.0.0.1", 12345);

            Encoder encode;
            std::string url = "/remove/" + encode.UTF8UrlEncode(updateCloudPath(object.path));


            //这里要优化成线程并发处理，不能阻塞在这
            req.HttpPost(url, "");

        }
        else if (object.action == FILE_ACTION_TRAP)
        {
            //暂时用来过滤修改事件
          // printf("check  trap  %s , %d !\n", wstringToString(object.path).c_str(), object.action);
            if (!objectList.empty())
            {
                auto objectTrap = objectList.front();
             //   printf("check  trap  %s , %d !\n", wstringToString(objectTrap.path).c_str(), objectTrap.action);
                if (objectTrap.action == FILE_ACTION_MODIFIED && objectTrap.path == object.path)
                {
                    objectList.pop_front();
           //         printf("found trap , jump up !\n");
                }
            }
        }
        else if (FILE_ACTION_DEHYDRATE == object.action)
        {
            HRESULT result;

            LARGE_INTEGER offset = {};
            LARGE_INTEGER length;
            length.QuadPart = MAXLONGLONG;


            winrt::handle placeholder(CreateFile(object.path.c_str(), 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr));
            wprintf(L"Dehydrating file %s\n", object.path.c_str());
            if (placeholder.get() == INVALID_HANDLE_VALUE)
                continue;

            result = CfDehydratePlaceholder(placeholder.get(), offset, length, CF_DEHYDRATE_FLAG_NONE, NULL);
            if (result != 0)
            {
                wprintf(L"CfDehydratePlaceholder  ret %x \n", result);
                if (result == 0x80070187)
                {
                    if (objectList.empty())
                        Sleep(1000);
                    objectList.push_back(object);
                    continue;
                }
            }
        }
        else if (object.action == FILE_ACTION_MODIFIED || object.action == FILE_ACTION_ADDED) {
            HRESULT result;
            USN  usn = 0;

            if (ignoreFile(wstringToString(object.path), true))
            {
                printf("ignoreFile %s \n", wstringToString(object.path).c_str());
                continue;
            }

            DWORD attrib = GetFileAttributes(object.path.c_str());
            
            if (attrib & FILE_ATTRIBUTE_DIRECTORY)
            {
                int ret = 0;
                printf("%s attrib FILE_ATTRIBUTE_DIRECTORY  \n", wstringToString(object.path).c_str());
                //新增时不用判断，直接设置
                ret = getCloudSyncState(object.path, FILE_FLAG_BACKUP_SEMANTICS);
           //     printf("ret %d \n", ret);
                if (ret == 0x80070178)
                {
                    //如果是移动，则需要把子目录都重复同步到云端 
                    TravelPath(object.path);
                
                    ret = setCloudSyncState(object.path, true, FILE_FLAG_BACKUP_SEMANTICS);
                    if (ret == -1)
                    {
                 //      printf(" file name %s , place holder error %x ! \n", wstringToString(object.path).c_str(), GetLastError());
                        objectList.push_back(object);

                        //这里是否会一直循环，需要确认
                        continue;
                    }
                }
                else if (ret == 0) {
                    //移动的也需要检查
                    TravelPath(object.path);

                    ret = setCloudSyncState(object.path, false, FILE_FLAG_BACKUP_SEMANTICS);
                    if (ret == -1)
                    {
                  //    printf(" file name %s , place holder error %x ! \n", wstringToString(object.path).c_str(), GetLastError());
                        objectList.push_back(object);

                        //这里是否会一直循环，需要确认
                        continue;
                    }
                }


               //需要云端记录空目录情况

            }
            else
            {

                LARGE_INTEGER offset = {};
                LARGE_INTEGER length;
                length.QuadPart = MAXLONGLONG;


              //  printf("%s attrib %x  \n", wstringToString(object.path).c_str(), attrib);

                if (attrib & FILE_ATTRIBUTE_PINNED)
                {
                    winrt::handle placeholder(CreateFile(object.path.c_str(), 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr));
                    wprintf(L"Hydrating file %s\n", object.path.c_str());
                    if (placeholder.get() == INVALID_HANDLE_VALUE)
                        continue;
                    
                    result = CfHydratePlaceholder(placeholder.get(), offset, length, CF_HYDRATE_FLAG_NONE, NULL);
                    if (result != 0)
                        wprintf(L"CfHydratePlaceholder  ret %x \n", result);

                }
                else if (attrib & FILE_ATTRIBUTE_UNPINNED)
                {
                    winrt::handle placeholder(CreateFile(object.path.c_str(), 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr));
                    wprintf(L"Dehydrating file %s\n", object.path.c_str());
                    if (placeholder.get() == INVALID_HANDLE_VALUE)
                        continue;

                    result = CfDehydratePlaceholder(placeholder.get(), offset, length, CF_DEHYDRATE_FLAG_NONE, NULL);
                    if (result != 0)
                    {
                        wprintf(L"CfDehydratePlaceholder  ret %x \n", result);
                        if (result == 0x80070187)
                        {
                            if (objectList.empty())
                                Sleep(1000);

                            object.action = FILE_ACTION_DEHYDRATE;

                            objectList.push_back(object);

                            continue;
                        }
                    }
#if 0
                    if (result != 0)
                    {
                        wprintf(L"CfDehydratePlaceholder  ret %x \n", result);
                        if (result == 0x80070178 || result == 0x80070179)
                        {
                            //非云文件时，需要先转成云文件
                            winrt::handle placeholder(CreateFile(object.path.c_str(), 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr));
                            result = CfConvertToPlaceholder(placeholder.get(), object.path.data(), (USHORT)(wcslen(object.path.data()) + 1) * sizeof(WCHAR), CF_CONVERT_FLAG_ENABLE_ON_DEMAND_POPULATION, &usn, NULL);
                            if (result != 0)
                                printf("CfConvertToPlaceholder HRESULT  %x , USN  %lld \n", result, usn);

                            //这里会触发再次同步
                            result = CfSetInSyncState(placeholder.get(), CF_IN_SYNC_STATE_IN_SYNC, CF_SET_IN_SYNC_FLAG_NONE, &usn);
                            if (result != 0)
                                printf("CfSetInSyncState HRESULT  %x , USN  %lld \n", result, usn);


                        }
                        else {
                            objectList.push_back(object);
                            Sleep(100);
                            continue;
                        }

                    }
#endif

                }
                else if (attrib & FILE_ATTRIBUTE_ARCHIVE)
                {
                    int ret = CF_IN_SYNC_STATE_NOT_IN_SYNC;

                    //新增默认为未同步
                    if (object.action != FILE_ACTION_ADDED)
                        ret = getCloudSyncState(object.path, 0);

                    if (ret == CF_IN_SYNC_STATE_IN_SYNC)
                        continue;
                    

                    //需要处理只是属性修改， 如打开WORD， 触发访问时间修改，而内容没变，则不需要上传 ？
                    if (object.action == FILE_ACTION_MODIFIED)
                    {

                    }

                    //ARCHIVE 文件需要被同步到云端
                    HttpRequest  req("127.0.0.1", 12345);

                    Encoder encode;
                    std::string url = "/upload/" + encode.UTF8UrlEncode(updateCloudPath(object.path));

                    //这里要优化成线程并发处理，不能阻塞在这·
                    ret = req.HttpPutFile(url, wstringToString(object.path.c_str()));
                    if (ret == -1 || ret == 1)
                    {
                        if (objectList.empty())
                            Sleep(1000);

                        //失败...
                        //回头再来
                        objectList.push_back(object);

                        //1也要重来
                        continue;
                    }


                 
                    if (ret == 0)
                    {
                        setCloudSyncState(object.path,true, 0);
                        
                       // printf("settrap \n");
                                                //插入一个陷井， 如果又进来， 则检查陷井
                        WatchObject  o{ object.path, FILE_ACTION_TRAP };
                        objectList.push_back(o);


                        //如果是子目录下文件同步完成，需要向上传递目录的同步状态
                     //   checkDirectSync(object.path);
                    }
                    

               
                }
            }

        }
        else if (object.action == FILE_ACTION_RENAMED_OLD_NAME) {
            //check back object 
            if (!objectList.empty())
            {
                printf(" old file %s\n", wstringToString(object.path).c_str());

                auto objectNewFile = objectList.front();
                if (objectNewFile.action == FILE_ACTION_RENAMED_NEW_NAME) {
                    objectList.pop_front();

                    printf(" new file %s\n", wstringToString(objectNewFile.path).c_str());

                    //这里可能是word的处理，先重命名成临时文件，再重命名回来，这里将重命名回来时，做为修改上传处理
                    if (ignoreFile(wstringToString(objectNewFile.path), true))
                    {
                        continue;
                    }

                    if (ignoreFile(wstringToString(object.path), false))
                    {
                        printf("push modify event  %s\n",  wstringToString(objectNewFile.path).c_str());


                        //转更新处理
                        WatchObject  o{ objectNewFile.path, FILE_ACTION_MODIFIED };
                        objectList.push_back(o);
                        continue;
                    }


                    DWORD attrib = GetFileAttributes(objectNewFile.path.c_str());
               
                    //macth action 
                    printf("old file %s , new file %s\n", wstringToString(object.path.c_str()).c_str(), wstringToString(objectNewFile.path.c_str()).c_str());
                    
                    Encoder encode;

                    std::string url = "/rename/" + encode.UTF8UrlEncode(updateCloudPath(object.path)) +  + "?newname=" + encode.UTF8UrlEncode(updateCloudPath(objectNewFile.path));
               
                    
                    HttpRequest  req("127.0.0.1", 12345);
                    int ret = req.HttpGet(url, NULL, NULL);
                    printf("ret %d\n", ret);

                    if (attrib & FILE_ATTRIBUTE_DIRECTORY)
                    {
                        //需要更新为同步状态图标
                        WatchObject  o{ objectNewFile.path, FILE_ACTION_MODIFIED };
                        objectList.push_back(o);
                    }
#if 0
                    else if (!objectList.empty())
                    {
                        auto objectNext = objectList.front();
                        if (objectNext.path == object.path)
                            objectList.pop_front();
                    }
#endif
             
                    continue;
                }
            }

            Sleep(10);
            objectList.push_back(object);
            
        }

        
    }

    printf("%s  exit \n", __FUNCTION__);
    service_exit_flag_ack = true;

}




//注水 | 脱水处理
void CloudProviderSyncRootWatcher::OnSyncRootFileChanges(_In_ std::list<WatchObject>& changes)
#if 1
{
    //将事件压到本地队列
    for (auto object : changes) {
        objectList.push_back(object);
    }
   
}
#endif
#if 0
{
    for (auto object : changes)
    {
        wprintf(L"Processing change for %s\n", object.path.c_str());
        if (object.action == FILE_ACTION_REMOVED)
        {
            wprintf(L"Remove file %s\n", object.path.c_str());
            HttpRequest  req("127.0.0.1", 12345);

            std::string localpath = wstringToString(object.path.c_str());
            std::string clientpath = wstringToString(ProviderFolderLocations::GetClientFolder()).c_str();
            localpath.erase(0, clientpath.length() + 1);

            std::string url = "/remove/" + localpath;

            //这里要优化成线程并发处理，不能阻塞在这
            req.HttpPost(url, "");
            continue;
        }

        DWORD attrib = GetFileAttributes(object.path.c_str());

        wprintf(L" attrib  %x \n", attrib);
        if (!(attrib & FILE_ATTRIBUTE_DIRECTORY))
        {
            winrt::handle placeholder(CreateFile(object.path.c_str(), 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr));

            LARGE_INTEGER offset = {};
            LARGE_INTEGER length;
            length.QuadPart = MAXLONGLONG;
            HRESULT result;

            if (attrib & FILE_ATTRIBUTE_PINNED)
            {
                wprintf(L"Hydrating file %s\n", object.path.c_str());
                result = CfHydratePlaceholder(placeholder.get(), offset, length, CF_HYDRATE_FLAG_NONE, NULL);
                wprintf(L"CfHydratePlaceholder  ret %x \n", result);

            }
            else if (attrib & FILE_ATTRIBUTE_UNPINNED)
            {
                wprintf(L"Dehydrating file %s\n", object.path.c_str());
                result = CfDehydratePlaceholder(placeholder.get(), offset, length, CF_DEHYDRATE_FLAG_NONE, NULL);
                wprintf(L"CfDehydratePlaceholder  ret %x \n", result);


            }
            else if (attrib & FILE_ATTRIBUTE_ARCHIVE)
            {
                //ARCHIVE 文件需要被同步到云端
                
                USN  usn = 0;
                HRESULT result;

                HttpRequest  req("127.0.0.1", 12345);
                
                std::string localpath = wstringToString(object.path.c_str());
                std::string clientpath = wstringToString(ProviderFolderLocations::GetClientFolder()).c_str();
                localpath.erase(0, clientpath.length() + 1);

                std::string url = "/upload/" + localpath;

             
                //这里要优化成线程并发处理，不能阻塞在这
                req.HttpPutFile(url, wstringToString(object.path.c_str()));

                std::wstring relativeName(object.path.c_str());

                result = CfConvertToPlaceholder(placeholder.get(), relativeName.data(), (USHORT)(wcslen(relativeName.data()) + 1) * sizeof(WCHAR), CF_CONVERT_FLAG_ENABLE_ON_DEMAND_POPULATION, &usn, NULL);
                if (result != 0)
                       printf("CfConvertToPlaceholder HRESULT  %x , USN  %lld \n", result, usn);

                result = CfSetInSyncState(placeholder.get(), CF_IN_SYNC_STATE_IN_SYNC, CF_SET_IN_SYNC_FLAG_NONE, &usn);
                if (result != 0)
                    printf("CfSetInSyncState HRESULT  %x , USN  %lld \n", result, usn);
            }


        }
    }
}
#endif

using namespace concurrency;

#include <concrt.h>

void CloudProviderSyncRootWatcher::InitDirectoryWatcher()
{
    service_exit_flag = false;

    
    CurrentScheduler::ScheduleTask(ServiceThread, NULL);


    // Set up a Directory Watcher on the client side to handle user's changing things there
    try
    {
        s_directoryWatcher.Initalize(ProviderFolderLocations::GetClientFolder(), OnSyncRootFileChanges);
    }
    catch (...)
    {
        wprintf(L"Could not init directory watcher.\n");
        throw;
    }
}

BOOL WINAPI
CloudProviderSyncRootWatcher::Stop(DWORD /*dwReason*/)
{
    s_shutdownWatcher = TRUE;
    return TRUE;
}

